package awss3

import (
	"bytes"
	"context"
	"fmt"

	"code.bydev.io/cht/customer/kyc_admin_service/internal/config"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/helper"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/kycprovider/dto"
	"git.bybit.com/svc/mod/pkg/bsecret/bsecretsecret"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	"go.uber.org/zap"
)

type AWSS3Manager = *s3Manager
type s3Manager struct {
	logger *zap.Logger
}

func New(logger *zap.Logger) AWSS3Manager {
	return &s3Manager{
		logger: logger,
	}
}

func (d *s3Manager) Download(ctx context.Context, hashID, key string) ([]byte, int, error) {
	bucket := config.GetAWSS3Config().Bucket
	defer helper.TimeCost(d.logger, "Download")()
	sess, err := helper.GetAWSS3Session()
	if err != nil {
		d.logger.Error("aws s3 session error", zap.Error(err))

		return nil, 0, err
	}
	secret := bsecretsecret.Secret([]byte(hashID))

	w := &aws.WriteAtBuffer{}
	downloader := s3manager.NewDownloader(sess)
	numBytes, err := downloader.DownloadWithContext(ctx, w,
		&s3.GetObjectInput{
			Bucket: aws.String(bucket),
			Key:    aws.String(key),
		})
	if err != nil {
		d.logger.Error("aws s3 download error", zap.Error(err))

		return nil, 0, err
	}
	d.logger.Info("aws s3 download success", zap.Int64("numBytes", numBytes))

	// 解密
	enData, err := secret.Reveal(w.Bytes())
	if err != nil {
		d.logger.Error("aws s3 secret Reveal error", zap.Error(err))
		return nil, 0, err
	}

	return enData, len(enData), nil
}

// Upload 上传文件
func (d *s3Manager) Upload(ctx context.Context, hashID string, doc *dto.Document) error {
	var (
		secret = bsecretsecret.Secret([]byte(hashID))
		bucket = config.GetAWSS3Config().Bucket
	)
	defer helper.TimeCost(d.logger, "Upload")()
	sess, err := helper.GetAWSS3Session()
	if err != nil {
		return err
	}
	uploader := s3manager.NewUploader(sess)

	doc.Key = fmt.Sprintf("%s/%s", hashID, doc.ID)
	doc.Bucket = bucket
	body, e := secret.Seal(doc.Data)
	if e != nil {
		return err
	}
	_, err = uploader.UploadWithContext(ctx, &s3manager.UploadInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(doc.Key),
		Body:   bytes.NewReader(body),
	})
	if err != nil {
		d.logger.Error("aws s3 upload error", zap.Error(err), zap.Any("doc.ID", doc.ID))
		return err
	}

	return nil
}
